﻿using AntdUI;
using FreeRedis;
using FreeSql.Internal;
using PosClient.Helper;
using PosClient.Interfaces;
using PosClient.Model;
using PosClient.Service;
using PosClient.Service.Actives;
using PosClient.ViewModel;
using PosClient.View;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using System.Reactive.Linq;
using PosClient.Event;
using Coldairarrow.Util;

namespace PosClient.ViewModel
{
    public class MainViewModel: ReactiveObject
    {
        public IScheduler _mainScheduler;

        public ViewModelActivator Activator { get; }

        public enum SaleModeEnum
        {
            Sale = 1, // 销售
            AfterSale = 2 // 退货
        }

        public enum RefundModeEnum
        {
            Order = 1, // 整单退货
            Good = 2 // 部分退货
        }

        #region 属性

        private BindingList<Plu> _PluList = new BindingList<Plu>();
        public BindingList<Plu> PluList
        {
            get => _PluList;
            set => this.RaiseAndSetIfChanged(ref _PluList, value);
        }

        private Plu _SelectPlu;
        public Plu SelectPlu
        {
            get => _SelectPlu;
            set => this.RaiseAndSetIfChanged(ref _SelectPlu, value);
        }

        private int _Index;
        public int Index
        {
            get => _Index;
            set => this.RaiseAndSetIfChanged(ref _Index, value);
        }

        private decimal _TotalCount;
        public decimal TotalCount
        {
            get => _TotalCount;
            set => this.RaiseAndSetIfChanged(ref _TotalCount, value);
        }

        private decimal _TotalAmount;
        public decimal TotalAmount
        {
            get => _TotalAmount;
            set => this.RaiseAndSetIfChanged(ref _TotalAmount, value);
        }

        private decimal _RemainPayAmount;
        public decimal RemainPayAmount
        {
            get => _RemainPayAmount;
            set => this.RaiseAndSetIfChanged(ref _RemainPayAmount, value);
        }

        private decimal _ExchangeAmount;
        public decimal ExchangeAmount
        {
            get => _ExchangeAmount;
            set => this.RaiseAndSetIfChanged(ref _ExchangeAmount, value);
        }

        private VipBase _VipBase = new VipBase();
        public VipBase VipBase
        {
            get => _VipBase;
            set => this.RaiseAndSetIfChanged(ref _VipBase, value);
        }

        private decimal _TotalDisAmount;
        public decimal TotalDisAmount
        {
            get => _TotalDisAmount;
            set => this.RaiseAndSetIfChanged(ref _TotalDisAmount, value);
        }

        private string _Barcode;
        public string Barcode
        {
            get => _Barcode;
            set => this.RaiseAndSetIfChanged(ref _Barcode, value);
        }

        private SaleModeEnum _SaleMode;
        public SaleModeEnum SaleMode
        {
            get => _SaleMode;
            set => this.RaiseAndSetIfChanged(ref _SaleMode, value);
        }

        private RefundModeEnum _RefundMode;
        public RefundModeEnum RefundMode
        {
            get => _RefundMode;
            set => this.RaiseAndSetIfChanged(ref _RefundMode, value);
        }

        [Reactive]
        public decimal Count { get; set; }


        private List<Keyboard> _Keyboards = new List<Keyboard>();
        public List<Keyboard> Keyboards
        {
            get => _Keyboards;
            set => this.RaiseAndSetIfChanged(ref _Keyboards, value);
        }

        private string _SubText;
        public string SubText
        {
            get => _SubText;
            set => this.RaiseAndSetIfChanged(ref _SubText, value);
        }

        private string _OrderNo;
        public string OrderNo
        {
            get => _OrderNo;
            set => this.RaiseAndSetIfChanged(ref _OrderNo, value);
        }

        private int _WorkNo;
        public int WorkNo
        {
            get => _WorkNo;
            set => this.RaiseAndSetIfChanged(ref _WorkNo, value);
        }

        private bool _Loading;
        public bool Loading
        {
            get => _Loading;
            set => this.RaiseAndSetIfChanged(ref _Loading, value);
        }

        #endregion

        #region Command

        /// <summary>
        /// 合计
        /// </summary>
        public ReactiveCommand<Unit, Unit> SummaryCommand { get; }

        /// <summary>
        /// 加1
        /// </summary>
        public ReactiveCommand<Unit, Unit> AddOneCommand { get; }

        /// <summary>
        /// 减1
        /// </summary>
        public ReactiveCommand<Unit, Unit> DelOneCommand { get; }

        /// <summary>
        /// 行情
        /// </summary>
        public ReactiveCommand<Unit, Unit> RemoveCommand { get; }

        /// <summary>
        /// 查询会员
        /// </summary>
        public ReactiveCommand<Unit, Unit> SearchVipCommand { get; }

        /// <summary>
        /// 获取Plu信息
        /// </summary>
        public ReactiveCommand<Unit, Result<Plu>> GetPluCommand { get; }

        /// <summary>
        /// 支付
        /// </summary>
        public ReactiveCommand<Unit, Unit> ConfirmPayCommand { get; }
        /// <summary>
        /// Vip打折
        /// </summary>
        public ReactiveCommand<Unit, Unit> VipDiscountCommand { get; set; }

        public ReactiveCommand<bool, Unit> ClearCartCommand { get; set; }

        public ReactiveCommand<Plu, Unit> MathUpdateCommand { get; set; }

        public ReactiveCommand<Unit, Unit> OpenPresentCommand { get; set; }

        public ReactiveCommand<string,decimal> ConvertVipDiscount { get; set; }

        public ReactiveCommand<Unit, Unit> OpenDownLoadCommand { get; set; }

        public ReactiveCommand<Unit, Unit> ChangePluPriceCommand { get; set; }
        #endregion

        public MainViewModel(IScheduler mainScheduler)
        {
            _mainScheduler = mainScheduler;
            Activator = new ViewModelActivator();

            Locator.CurrentMutable.RegisterLazySingleton(() => new PayView());
            Locator.CurrentMutable.RegisterLazySingleton(() => new PayViewModel(mainScheduler));

            var canPay = this.WhenAnyValue(vm => vm.PluList.Count, (index) => index > 0);

            // 配置雪花Id
            new IdHelperBootstrapper().SetWorkderId(DateTime.Now.Second).Boot();

            SummaryCommand = ReactiveCommand.Create(SummaryCommandImpl);
            AddOneCommand = ReactiveCommand.Create(AddOneCommandImpl);
            DelOneCommand = ReactiveCommand.Create(DelOneCommandImpl);
            RemoveCommand = ReactiveCommand.Create(RemoveCommandImpl);
            SearchVipCommand = ReactiveCommand.Create(SearchVipCommandImpl);
            GetPluCommand = ReactiveCommand.Create(GetPluCommandImpl);
            ConfirmPayCommand = ReactiveCommand.Create(ConfirmPayCommandImpl, canPay,mainScheduler);
            VipDiscountCommand = ReactiveCommand.Create(VipDiscountCommandImpl);
            ClearCartCommand = ReactiveCommand.Create<bool>(ClearCartCommandImpl);
            MathUpdateCommand = ReactiveCommand.Create<Plu>(MathUpdateCommandImpl);
            OpenPresentCommand = ReactiveCommand.Create(OpenPresentCommandImpl);
            ConvertVipDiscount = ReactiveCommand.Create<string, decimal>(ConvertVipDiscountImpl);
            OpenDownLoadCommand = ReactiveCommand.Create(OpenDownLoadCommandImpl);
            ChangePluPriceCommand = ReactiveCommand.Create(ChangePluPriceCommandImpl);

            OrderNo = OrderService.GetCurrentOrderNo();

            this.WhenAnyValue(vm => vm.VipBase.VipCode).Subscribe(m =>
            {
                if (!string.IsNullOrEmpty(m))
                {
                    VipDiscountCommand.Execute().Subscribe();
                }
            });

            this.WhenAnyValue(vm => vm.Loading).Do(x =>
            {
                if (!x)
                {
                    // 这里是关键，一定要在UI线程触发更新
                    mainScheduler.Schedule(new Action(() =>
                    {
                        SubText = string.Empty;
                    }));
                }
            }).Subscribe();

            InitListen();

            var conn = FreeClient.Redis;
            var keys = conn.HKeys(RedisKey.Redis_Keyboard);
            if (keys.Length > 0)
            {
                foreach (var key in keys)
                {
                    var json = conn.HGet(RedisKey.Redis_Keyboard, key);
                    var keyboard = JsonConvert.DeserializeObject<Keyboard>(json);
                    Keyboards.Add(keyboard);
                }
            }

        }

        private void InitListen()
        {
            MessageBus.Current.Listen<SearchVipEventArgs>()
                .ObserveOn(RxApp.MainThreadScheduler)
                .Subscribe(e =>
                {
                    if (e.Vip.VipCode != null)
                    {
                        VipBase = e.Vip;
                    }
                });
        }

        private void SummaryCommandImpl()
        {
            TotalAmount = PluList.Sum(x => x.Amount);
            TotalCount = PluList.Sum(x => x.Count);
            TotalDisAmount = PluList.Sum(x => x.DisAmount);
        }

        private void AddOneCommandImpl()
        {
            if (SelectPlu != null)
            {
                SelectPlu.Count++;
                SelectPlu.Summary();
                Index = PluList.IndexOf(SelectPlu);
                SummaryCommandImpl();
            }
        }

        private void DelOneCommandImpl()
        {
            if (SelectPlu != null)
            {
                SelectPlu.Count--;
                SelectPlu.Summary();
                Index = PluList.IndexOf(SelectPlu);
                SummaryCommandImpl();
            }
        }

        private void RemoveCommandImpl()
        {
            if (Index > -1)
            {
                if (PluList.Count == 0) return;
                Logger.AuditLogger.Audit($"删除商品 {PluList[Index]}");
                if (SelectPlu != null)
                {
                    PluList.RemoveAt(Index);
                }
            }
        }

        private void SearchVipCommandImpl()
        {
            Logger.AuditLogger.Audit($"进入查询会员窗口");
            SearchVipView searchVipView = new SearchVipView();
            searchVipView.ShowDialog();
        }

        private Result<Plu> GetPluCommandImpl()
        {
            Result<Plu> result = new Result<Plu>()
            {
                Success = true,
                Message = "请求成功"
            };
            if (!string.IsNullOrEmpty(Barcode))
            {
                var pluService = Locator.Current.GetService<IPluService>();
                pluService.SearchBarcode(Barcode,out Plu plu);
                if (plu == null)
                {
                    pluService.SearchPlu(Barcode, out plu);
                }
                if (plu != null)
                {
                    MathUpdateCommandImpl(plu);
                }
                else
                {
                    result.Success = false;
                    result.Message = "未找到该条码";
                }
            }
            else
            {
                result.Success = false;
                result.Message = "请输入条码";
            }
            return result;
        }

        private void MathUpdateCommandImpl(Plu plu)
        {
            if (plu.Count == 0)
            {
                plu.Count = Count;
            }
            if (plu.Tag == Plu.PluTag.Cut || plu.Tag == Plu.PluTag.Present)
            {
                plu.OriginAmount = plu.OriginPrice * plu.Count;
                plu.Amount = plu.GetBestAmount();
                plu.DisAmount = plu.OriginAmount - plu.Amount;
                plu.Seq = PluList.Count + 1;
                // 合并商品
                Plu cartplu = PluList.Where(g => g.PluCode == plu.PluCode &&
                    ((g.Tag == Plu.PluTag.Cut && g.Barcode == plu.Barcode) || (g.Tag == Plu.PluTag.Present)))
                    .FirstOrDefault();
                if (cartplu != null)
                {
                    cartplu.Count += Count;
                    cartplu.Amount += plu.Amount;
                    cartplu.OriginAmount += plu.OriginAmount;
                    cartplu.DisAmount += plu.DisAmount;
                    plu = cartplu;
                }
                else

                {
                    PluList.Add((Plu)ToolService.DeepCopy(plu));
                }
                SelectPlu = plu;
                Barcode = string.Empty;
                Count = 1;
            }
            else
            {
                // 设置初始数据
                if (plu.OriginPrice == 0)
                {
                    plu.OriginPrice = plu.Price;
                }

                // 检查会员价
                if (plu.CanDiscount == "1" )
                {
                    DiscountByMemberCommandImpl(plu);
                }
                plu.Summary();
                plu.Seq = PluList.Count + 1;
                plu = AddorUpdateCartCommandImpl(plu);
                SelectPlu = plu;
                Barcode = string.Empty;
                Count = 1;
            }
            SummaryCommandImpl();
        }

        private Plu AddorUpdateCartCommandImpl(Plu plu)
        {
            var redis = FreeClient.Sqlite;
            Plu cartPlu = PluList.Where(g => g.PluCode == plu.PluCode
                && g.Tag != Plu.PluTag.Cut
                && g.Tag != Plu.PluTag.Change
                && g.Tag != Plu.PluTag.Present
                //&& g.CategoryCode.Substring(0,2) != "02"
                ).FirstOrDefault();
            if (cartPlu != null)
            {
                cartPlu.Count += plu.Count;
                cartPlu.Amount += plu.Amount;
                // cartplu.Price = Math.Round(cartplu.Amount / cartplu.Count, 2, MidpointRounding.AwayFromZero);
                cartPlu.OriginAmount += plu.OriginAmount;
                cartPlu.DisAmount += plu.DisAmount;
            }
            else
            {
                if (plu.CanDiscount == "1" && VipBase.VipLevel != null && !string.IsNullOrEmpty(VipBase.VipLevel.LevelType.ToString()))
                {
                    int precision = 2;
                    decimal discount = ConvertVipDiscountImpl(VipBase.VipLevel.LevelCode);
                    decimal priceAfterDiscount = Math.Round(plu.OriginPrice * discount, precision, MidpointRounding.AwayFromZero);
                    plu.VipPrice = priceAfterDiscount;
                    plu.Tag = Plu.PluTag.Vip;
                    plu.Summary();
                }
                PluList.Add(plu);
            }
            SummaryCommandImpl();
            return plu;
        }


        private void ConfirmPayCommandImpl()
        {
            SummaryCommandImpl();
            IActionService payView = new PayActive();
            payView.Action(this);
        }

        private decimal ConvertVipDiscountImpl(string vipcode)
        {
            var redis = FreeClient.Redis;
            {
                var exists = redis.HExists(RedisKey.Redis_VipLevel, vipcode);
                if (exists)
                {
                    var json = redis.HGet(RedisKey.Redis_VipLevel, vipcode);
                    VipLevel vipLevel = JsonConvert.DeserializeObject<VipLevel>(json);
                    return vipLevel.DisCount / 100m;
                }
                else
                {
                    return 0.0m;
                }
            }
        }

        private void VipDiscountCommandImpl()
        {
            //>0为打折会员，暂定1打98折，2打95，3打93，4打90
            if (VipBase != null && VipBase.VipLevel != null && VipBase.VipLevel.LevelType > 0)
            {
                foreach (Plu plu in PluList.Where(x => x.Tag != Plu.PluTag.Promote 
                                                     && x.Tag != Plu.PluTag.Cut 
                                                     && x.Tag != Plu.PluTag.Present 
                                                     && x.Tag != Plu.PluTag.Change
                                                     && x.Tag != Plu.PluTag.ExChange
                                                     ))
                {
                    if (plu.CanDiscount == "1")
                    {
                        int precision = 2;
                        decimal discount = ConvertVipDiscountImpl(VipBase.VipLevel.LevelCode);
                        decimal priceAfterDiscount = Math.Round(plu.OriginPrice * discount, precision, MidpointRounding.AwayFromZero);
                        plu.VipPrice = priceAfterDiscount;
                        plu.Tag = Plu.PluTag.Vip;
                        plu.Summary();
                        SummaryCommandImpl();
                    }
                }
            }
        }

        private void DiscountByMemberCommandImpl(Plu plu)
        {
            //>0为打折会员，暂定1打98折，2打95，3打93，4打90
            if (VipBase != null && VipBase.VipLevel != null && VipBase.VipLevel.LevelName != "游客" && VipBase.VipCode != null &&
                plu.Tag != Plu.PluTag.Cut && plu.Tag != Plu.PluTag.Present &&
                plu.Tag != Plu.PluTag.Change)
            {
                if (plu.CanDiscount == "1")
                {
                    int precision = 2;
                    decimal discount = ConvertVipDiscountImpl(VipBase.VipLevel.LevelCode);
                    decimal priceAfterDiscount = Math.Round(plu.OriginPrice * discount, precision, MidpointRounding.AwayFromZero);
                    plu.VipPrice = priceAfterDiscount;
                    plu.Tag = Plu.PluTag.Vip;
                    plu.Summary();
                    SummaryCommandImpl();
                }
                SummaryCommandImpl();
            }
        }

        private void ClearCartCommandImpl(bool isShow = true)
        {
            if (VipBase != null)
            {
                VipBase = new VipBase
                {
                    VipCode = string.Format(" "),
                    PointCurrent = 0,
                    DepositCurrent = 0,
                    VipLevel = new VipLevel()
                    { 
                        LevelCode = "- -",
                        LevelName = "游客",
                        LevelType = -1
                    }
                };
            }
            SaleMode = SaleModeEnum.Sale;
            TotalAmount = 0;
            TotalCount = 0;
            if (PluList.Count > 0)
            {
                if (isShow)
                {
                    if (MessageBox.Show("确认要清空购物车吗？", "提醒", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) == DialogResult.Yes)
                    {
                        // 清空购物车
                        Index = -1;
                        TotalAmount = 0;
                        TotalCount = 0;
                        SaleMode = SaleModeEnum.Sale;
                        Barcode = string.Empty;
                        SelectPlu = null;
                        PluList.Clear();
                    }
                }
                else
                {
                    // 清空购物车
                    Index = -1;
                    TotalAmount = 0;
                    TotalCount = 0;
                    SaleMode = SaleModeEnum.Sale;
                    Barcode = string.Empty;
                    SelectPlu = null;
                    PluList.Clear();
                }
            }
        }

        private void OpenPresentCommandImpl()
        {
            IActionService action = new PresentActive();
            action.Action(this);
        }

        private void OpenDownLoadCommandImpl()
        {
            IActionService action = new DownLoadActive();
            action.Action(this);
        }

        private void ChangePluPriceCommandImpl()
        {
            IActionService action = new ChangePluPriceActive();
            action.Action(this);
        }
    }
}
